﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;

namespace System.Linq
{

    public enum DynamicWhereType
    {
        /// <summary>
        /// 相等比较
        /// </summary>
        Equal,
        /// <summary>
        /// 包含 目前仅支持string类型的数据类型
        /// </summary>
        Contains,
        /// <summary>
        /// 不包含 目前仅支持string类型的数据类型
        /// </summary>
        NotContains,
        /// <summary>
        /// 匹配开头 目前仅支持string类型的数据类型
        /// </summary>
        StartsWith,
        /// <summary>
        /// 匹配结尾 目前仅支持string类型的数据类型
        /// </summary>
        EndsWith,
        /// <summary>
        /// 大于
        /// </summary>
        GreaterThan,
        /// <summary>
        /// 小于
        /// </summary>
        LessThan,
        /// <summary>
        /// 大于等于
        /// </summary>
        GreaterThanOrEqual,
        /// <summary>
        /// 小于等于
        /// </summary>
        LessThanOrEqual

    }
    /// <summary>
    /// where查询表达式的扩展
    /// </summary>
    public static class WhereExpressionTree
    {
        /// <summary>
        /// where 动态查询的大于
        /// </summary>
        public static IQueryable<T> WhereDynamic<T>(this IQueryable<T> source, string key, DynamicWhereType dynamicWhereType, object value) where T : class
        {
            //获取拼装的lambda
            var lambda = source.GetLambda(key, dynamicWhereType, value);
            //创建一个where条件
            var where = Expression.Call(
                //工厂对象
                typeof(Queryable),
                //方法名
                "Where",
                //类型
                new Type[] { typeof(T) },
                new Expression[]
                {
                    source.Expression,
              lambda
                }
                );
            //创建一个查询
            return source.Provider.CreateQuery<T>(where);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <param name="dynamicWhereType"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private static Expression<Func<T, bool>> GetLambda<T>(this IQueryable<T> source, string key, DynamicWhereType dynamicWhereType, object value)
        {
            //定义一个对象参数
            ParameterExpression parameter = Expression.Parameter(typeof(T), typeof(T).Name);

            //获取对象的字段
            var fieid = Expression.Property(parameter, typeof(T).GetProperty(key));

            //返回值
            Expression<Func<T, bool>> lambda = default;
            switch (dynamicWhereType)
            {
                case DynamicWhereType.Equal:
                    lambda = Expression.Lambda<Func<T, bool>>(Expression.Equal(fieid, Expression.Constant(value)), new ParameterExpression[] { parameter });
                    break;
                case DynamicWhereType.Contains:
                    lambda = Expression.Lambda<Func<T, bool>>(
              Expression.Call(fieid, "Contains", null, new Expression[]
               { Expression.Constant(value)
               }), parameter
            );
                    break;
                case DynamicWhereType.NotContains:
                    lambda = Expression.Lambda<Func<T, bool>>(
                        Expression.Not(
                        Expression.Call(fieid, "Contains", null, new Expression[]
                        { Expression.Constant(value)
                        })), parameter
                        );
                    break;
                case DynamicWhereType.StartsWith:
                    lambda = Expression.Lambda<Func<T, bool>>(
             Expression.Call(fieid, "StartsWith", null, new Expression[]
              { Expression.Constant(value)
              }), parameter
           );
                    break;
                case DynamicWhereType.EndsWith:
                    lambda = Expression.Lambda<Func<T, bool>>(
           Expression.Call(fieid, "EndsWith", null, new Expression[]
            { Expression.Constant(value)
            }), parameter
         );
                    break;
                case DynamicWhereType.GreaterThan:
                    if (value.GetType() == typeof(string))
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(
                            Expression.GreaterThan(
                           Expression.Call(fieid, "CompareTo", null, new Expression[]
                            {
                                Expression.Constant(value)
                            }),
                           Expression.Constant(0)), parameter
                        );
                    }
                    else
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(fieid, Expression.Constant(value)), new ParameterExpression[] { parameter });
                    }
                    break;
                case DynamicWhereType.LessThan:
                    if (value.GetType() == typeof(string))
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(
                           Expression.LeftShift(
                          Expression.Call(fieid, "CompareTo", null, new Expression[]
                           { Expression.Constant(value)
                           }), Expression.Constant(0)), parameter
                       );
                    }
                    else
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(Expression.LessThan(fieid, Expression.Constant(value)), new ParameterExpression[] { parameter });
                    }
                    break;
                case DynamicWhereType.GreaterThanOrEqual:
                    if (value.GetType() == typeof(string))
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(
                           Expression.GreaterThanOrEqual(
                          Expression.Call(fieid, "CompareTo", null, new Expression[]
                           { Expression.Constant(value)
                           }), Expression.Constant(0)), parameter
                       );
                    }
                    else
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(fieid, Expression.Constant(value)), new ParameterExpression[] { parameter });
                    }

                    break;
                case DynamicWhereType.LessThanOrEqual:
                    if (value.GetType() == typeof(string))
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(
                           Expression.LessThanOrEqual(
                          Expression.Call(fieid, "CompareTo", null, new Expression[]
                           { Expression.Constant(value)
                           }), Expression.Constant(0)), parameter
                       );
                    }
                    else
                    {
                        lambda = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(fieid, Expression.Constant(value)), new ParameterExpression[] { parameter });
                    }

                    break;
                default:
                    throw new InvalidOperationException("不支持的实现");
            }
            return lambda;
        }
    }
}
